#!/bin/sh
#
# $Header: mkinitramfs-ll/init                            Exp $
# $Author: (c) 2011-19 tokiclover <tokiclover@gmail.com>  Exp $
# $License: 2-clause/new/simplified BSD                   Exp $
# $Version: 0.22.2 2019/01/12 12:33:03                    Exp $
#
# WARNING: USE AT YOUR OWN RISK! EVERYTHING IS GIVEN “AS IS”, SEE COPYING FILE
#

CHECK_ENV=true
init=/sbin/init
confdir=/etc/mkinitramfs-ll
libdir=/lib/mkinitramfs-ll
logfile=$0.log
mntdir=/mnt/tok
newroot=/newroot
splashd=false
NULL=/dev/null
export SHELL=/bin/sh
export HOME=/root
export PATH=/bin:/sbin:/usr/bin:/usr/sbin
export TERM=linux
exec 3>$logfile
logfd=3
PS1='-($(tty | cut -c6-):$PWD)-# '
PS2='-# '

# @FUNCTION: Handle fatal error
# @ARG: <msg>
die() {
	local _ret=$?
	[ -n "$@" ] && msg -e "[$_ret]: $@"
	echo -e "$color_fg_red>>>$color_rst Dropping to a Rescue Shell"
	$splashd && splashd_stop
	debug rescue_shell || debug $SHELL -lim
}

. $libdir/functions || $SHELL -lim
eval_colors
name=init

# @FUNCTION: Shell Run Level helper
# @ARG: <level>
level() {
	echo -e "$color_fg_grn>>>$color_rst Switching to init shell run level $color_fg_blu$1$color_rst"
	level=$1

	local _f
	for _f in $(ls $libdir/${1}-* 2>$NULL); do
		dohook "$_f"
	done
	case "$level" in
		("$rescue_shell") debug die;;
	esac
	return 0
}

# @FUNCTION: Splash daemon helper
splashd() {
	$CHECK_ENV && debug -d bck fbcondecor_helper splash_util
	local IFS="${IFS}," _opt _opts cachedir event mode theme
	
	event="$(grep -Hsi keyboard /sys/class/input/input*/name | \
		sed -e 's#.*input\([0-9]*\)/name.*#event\1#')"
:	${cachedir:=/run/splash/cache}
:	${BOOT_MSG:="Booting the system (\$progress%)... Press F2 for verbose mode."}
:	${splash_fifo=$cachedir/.splash}
	
	for _opt in $splash; do
		case "${_opt%:*}" in
			(fad*) _opts="set effects $_opt";;
			(silent|verbose) mode="$_opt"   ;;
			(tty) CONSOLE=/dev/"${_opt/:/}" ;;
			(theme) theme="${_opt#*:}"      ;;
		esac
	done

	[ -d "$cachedir" ] || mkdir -p $cachedir
	debug mkfifo $splash_fifo
	debug splash_util -d -ms -t $theme && splashd=true
	[ -n "$_opts" ] && debug splashd_cmd $_opts
	debug splashd_cmd "set ${mode:-verbose}"
	debug splashd_cmd "set event dev /dev/input/$event"
	debug splashd_cmd "set autoverbose 0"
}

# @FUNCTION: Resume helper (support SwSusp/TuxOnIce)
# @ARG: <[type:]dev[:signature]>
resume() {
	local _asw _dev=$1 _img_sz _hpr
	grep -q $mntdir /proc/mounts && debug -d umount -l $mntdir

	if [ -d /sys/power/tuxonice ]; then
		if $splashd; then
			[ -n "$theme" ] &&
			debug ln -sf "/etc/splash/$theme" /etc/splash/tuxonice
			_hpr=tuxoniceui_fbsplash
		else
			_hpr=tuxoniceui_text
		fi
		$CHECK_ENV && debug -d check_bin $_hpr && _hpr="$(type -p $_hpr)"

		debug MODPROBE tuxonice
		echo $_hpr >/sys/power/tuxonice/user_interface/program
		echo $_dev >/sys/power/tuxonice/resume

		read _img </sys/power/tuxonice/image_exists
		if [ "$_img_sz" = "1" ]; then
			echo >/sys/power/tuxonice/image_exists
		else
			echo >/sys/power/tuxonice/do_resume
		fi
	elif [ -f /sys/power/resume ]; then
		debug MODPROBE swsusp
		echo platform >/sys/power/disk # or 'shutdown'  if ACPI does not work
		echo disk >/sys/power/state

		local _node=${_dev#*:}
		[ -h "$_node" ] && _node=$(readlink $_node)
		read _node  </sys/class/block/${_node#*/}/dev
		echo $_node >/sys/power/resume

		read _img_sz </sys/power/image_exists
		if [ "$_img_sz" != "0" ]; then
			echo $_node >/sys/power/resume
		else
			echo 0 >/sys/power/image_size
		fi
	fi
}

# -*- Initialisation -*-

debug umask 0077
debug mkdir -p dev/pts proc run sys $newroot $mntdir

debug mount -t proc proc /proc
debug mount -t sysfs sysfs /sys
if grep -q devtmpfs /proc/filesystems; then
	debug mount -t devtmpfs devtmpfs /dev
else
	debug mount -t tmpfs -o exec,mode=755 tmpfs /dev
fi
echo >/dev/mdev.seq
[ -x /sbin/mdev ] && mdev=/sbin/mdev || mdev="/bin/busybox mdev"
debug -d $mdev -s
echo $mdev >/proc/sys/kernel/hotplug

debug mount -t tmpfs -o mode=755,size=1% tmpfs /run

CMDLINE="$(cat /proc/cmdline)"
for arg in $CMDLINE; do
	case "$arg" in
		([Rr][Ee][Ss][Cc][Uu][Ee]*|[Rr][Ss][Hh]*) rescue_shell=1;;
		(ro|rw) rootflags="${rootflags:+$rootflags,}$arg";;
		([Cbcdefhiklmnrsvz]*=*) eval "$arg" ;;
	esac
done
:	${rootfstype:=$rootfs}

if [ -n "$level" ]; then
	rescue_shell="${level%:*}"
fi

case "$env" in
	(""|*:*) ENV=true;;
	(*)
	yesno "${env:-YES}"
	case "$?" in
		(0) ENV=true ;;
		(*) ENV=false;;
	esac
	;;
esac
$ENV && [ -f $confdir/env ] &&
while read _line; do
	case "$_line" in
		(confdir=*|libdir=*|HOME=*|keymode=*|logfile=*|mntdir=*|newroot=*) ;;
		(PATH=*|rescue_shell=*|NULL=*|splashd=*|SHELL=*|name=*) ;;
		([A-Za-z]*=*)
		case "$env" in
			(*:${_line%%=*}:*) ;;
			(*) eval "$_line"  ;;
		esac;;
	esac
done < $confdir/env
$CHECK_ENV && debug check_applet

CUT "dmesg" "$debug" ":" "2" "-s"
debug="${debug%:*}"
case "$debug" in
	(*l*)
	keeplog=true debug="${debug/l/}"
	exec 2>&3
	;;
esac
[ -n "$debug" ]  && set -${debug/e/}
[ -n "$dmesg" ]  && debug dmesg -n $dmesg
dmesg=

[ -f $confdir/module-boot ] &&
for _m in $(cat $confdir/module-boot); do
	debug MODPROBE $_m
done
for _m in $(echo "$module" | sed 's/[:,]/ /g'); do
	debug MODPROBE $_m
done

[ -h /dev/fd     ] || debug ln -fns /proc/self/fd /dev/fd
[ -h /dev/stderr ] || debug ln -fns fd/2 /dev/stderr
[ -h /dev/stdin  ] || debug ln -fns fd/0 /dev/stdin
[ -h /dev/stdout ] || debug ln -fns fd/1 /dev/stdout

:	${CONSOLE:=${console:-/dev/console}}
[ "${CONSOLE/dev}" != "$CONSOLE" ] || CONSOLE="/dev/$CONSOLE"
[ -c $CONSOLE ] || CONSOLE=/dev/console
exec 0<$CONSOLE 1>$CONSOLE 2>&1
eval_colors
set >/environ

if [ -n "$video" ]; then
	debug dohook "$libdir/fb-video"
fi
if [ -n "$splash" ]; then
	begin "Starting Splash"
	splashd
	end "$?"
fi

# -*- Font and keymap -*-

if [ -n "$keymap" ]; then
	CUT "font" "$keymap" "2" ":" "-s"
	kmap="${keymap%:*}"
fi
[ -z "$font" ] && [ -f "$confdir/font" ] && font=$(cat $confdir/font)
[ -z "$kmap" ] && [ -f "$confdir/kmap" ] && kmap=$(cat $confdir/kmap)

[ -n "$font" ] &&
for file in /usr/share/consolefonts/$font*; do
	[ -f "$file" ] && debug loadfont < $file && break
done
[ -n "$kmap" ] &&
for file in /usr/share/keymaps/$kmap*; do
	[ -f "$file" ] && debug loadkmap < $file && break
done
unset file font kmap

# -*- Logo and or boot message -*-
level 1
[ -f /etc/issue.logo ] && cat /etc/issue.logo
if debug test -f /etc/issue; then
clear
while read _line; do
	msg -i "$_line"
done </etc/issue
fi

# -*- Hooks -*-
level 2
for _h in bcache btrfs zfs zram; do
	eval [ \"x\$$_h\" != x ] && hook="$hook $_h"
done
hook="$(echo $hook | sed -e 's/[:,]/ /g')"
for _h in $hook; do
	if [ -e "$libdir/$_h" ]; then
		debug dohook "$libdir/$_h"
	else
		error "$_h not found"
	fi
done
_h=

# -*- Swap/Resume -*-

# SWAP should be set if available
if [ -n "$swap" ]; then
	level 2s
	if [ -z "$SWAP" ]; then
		begin "Enabling swap device"
		get_dev "$swap" "SWAP" "2"
		end "$?"
	fi
fi
# RESU should be set if available
if [ -n "$resume" ]; then
	level 2r
	if [ -z "$RESU" ] && [ "$resume" != "swap" ]; then
		begin "Starting Resume"
		get_dev "$resume" "RESU" "3"
		end "$?"
	fi
	debug resume "${RESU:-$SWAP}"
fi

# -*- Root -*-

level 3
# ROOT should be set if available
mount_rootfs() {
	local fstype="${rootfstype%:*}" check
	CUT "check" "$rootfstype" ":" "2" "-s"
	debug -d get_dev "$root" "ROOT" "1"

	level 3f
	if [ -n "$check" ]; then
		yesno $check && check=-d || check=-e
		debug $check fsck ${fstype:+-t} $fstype $ROOT
	fi
	level 3m
	debug mount ${rootflags:+-o} $rootflags ${fstype:+-t} $fstype $ROOT $newroot ||
		die "Failed to mount rootfs"
}
if [ -z "$ROOT" ]; then
	begin "Mounting RootFS"
	mount_rootfs
	end "$?"
fi
if [ -n "$squashd" ]; then
	level 3s
	begin "Mounting Squashed FileSystems"
	squashd "$squashd"
	end "$?"
fi

# -*- Clean up and switch -*-
level 4

for _k in $loopback_key; do
	debug dmclose "$_k"
done
for _d in $loopback_dev; do
	debug losetup -d $_d
done

[ "$keymode" = "gpg" ] && debug RMMOD gpg
if grep -q $mntdir /proc/mounts; then
	debug -d umount -l $mntdir
	debug RMMOD remdev
fi
if [ -n "$fsmount" -o -n "$fstab" ]; then
	level 4m
	begin "Mounting FileSystems"
	fsmount $fsmount $fstab
	end "$?"
fi

level 4u
#
# FIXME: is this necessary?
#
$splashd && debug splashd_stop

if [ -n "$keeplog" ]; then
	cp $logfile $newroot
	cp $logfile /run
fi

echo >/proc/sys/kernel/hotplug
for _dir in /run /sys /dev /proc; do
	if [ "${SYSFS/${_dir#/}}" != "$SYSFS" ]; then
		begin "Moving $_dir to $newroot"
		mkdir -p $newroot$_dir
		mount -o move $_dir $newroot$_dir >$NULL 2>&1
	else
		begin "Unmounting $_dir"
		umount -l $_dir >$NULL >&1
	fi
	end "$?"
done

level 4s
set >/environ
echo -e "$color_fg_grn>>>$color_rst Switching Root"
exec 3>&-
while read _env; do
	case "$_env" in
		init=*) : ;;
		[Cbcdefhiklmnrsz]*=*) unset "${_env%%=*}" ;;
	esac
done </environ
exec switch_root /newroot ${init:-/sbin/init}

echo -e "$color_fg_red>>>$color_rst Failed to switch root!"
exec >${SHELL:-/bin/sh} -lim

#
# vim:fenc=utf-8:ft=sh:ci:pi:sts=0:sw=4:ts=4:
#
